package com.hex.ds.hdrs.agent.service;

import com.hex.ds.hdrs.agent.dao.AgentDao;
import com.hex.ds.hdrs.agent.po.AgentConf;
import com.hex.ds.hdrs.app.po.AppConf;
import com.hex.ds.hdrs.app.service.AppManager;
import com.hex.ds.hdrs.app.service.AppSession;
import com.hex.ds.hdrs.center.po.CenterConf;
import com.hex.ds.hdrs.center.vo.RegisterReq;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.constant.ErrorCode;
import com.hex.ds.hdrs.common.exception.BizException;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.common.utils.ListUtil;
import com.hex.ds.hdrs.engine.service.ManagerService;
import com.hex.ds.hdrs.log.service.LogService;
import com.hex.ds.hdrs.period.task.dto.ScheduleTask;
import com.hex.ds.hdrs.period.task.dto.TaskInfo;
import com.hex.ds.hdrs.period.task.po.PeriodTask;
import com.hex.ds.hdrs.period.task.util.FilterTaskHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @Package: com.hex.ds.hdrs.engine.manager
 * @ClassName AgentManager
 * @Description: Agent 管理
 * @Author: jd.chen
 * @Date 2021/7/5 17:53
 * @Version v1.0
 **/
@Slf4j
@Component
public class AgentManager implements ApplicationContextAware {

    private static ApplicationContext context;

    // 有效的AgentSession集合
    private List<AgentSession> agentSessionList = new ArrayList<>();
    // 无效的的AgentSession集合
    private List<AgentSession> notValidAgentSessionList = new ArrayList<>();
    // 有效的<agentCode,AgentSession>
    private Map<String, AgentSession> agentSessionMap = new HashMap<>();

    @Autowired
    private AppManager appManager;
    @Autowired
    private ManagerService managerService;
    @Autowired
    private LogService logService;
    @Autowired
    private AgentDao agentDao;

    @Autowired
    private AgentConfService agentConfService;

    @Value("${dispatcher.send.failLimit}")
    private int disSendFailLimit;
    @Value("${dispatcher.send.sleep}")
    private int disSendSleep;


    /**
     * 创建agentSession
     *
     * @param agentCode
     * @return
     */
    public AgentSession crtAgentSession(String agentCode) {
        AgentConf agentConf = agentConfService.qryAgentConfByAgentCode(agentCode);
        if (Const.AGENT_STATUS_STOP.equals(agentConf.getAgentStatus())) {
            log.warn("【AgentManager.crtAgentSession】agent已停用=====");
            throw new BizException(ErrorCode.ERROR_800010);
        }
        AgentSession agentSession = getSession(agentCode);
        if (agentSession == null) {
            return this.createAgentSession(agentConf);
        } else if (Const.AGENT_STATUS_STOP.equals(agentSession.getStatus())) {
            agentSession.setLstHeartBeatTs(HdrsDateUtil.getMillis(new Date()));
            continueAgent(agentCode);
        }
        return agentSession;
    }

    public AgentSession checkAgentSession(String agentCode){
        AgentSession agentSession = getSession(agentCode);
        if (Const.AGENT_STATUS_STOP.equals(agentSession.getStatus())) {
            agentSession.setLstHeartBeatTs(HdrsDateUtil.getMillis(new Date()));
            continueAgent(agentCode);
        }
        return agentSession;
    }

    /**
     * 获取节点信息配置
     *
     * @param agentCode
     */
    public AgentSession getAgentSession(String agentCode) {
        AgentSession agentSession = getSession(agentCode);
        if (agentSession == null) {
            log.warn("【{}】【AgentManager.getAgentSession】agentSession不存在", agentCode);
            throw new BizException(ErrorCode.ERROR_800020);
        } else {
            if (Const.AGENT_STATUS_STOP.equals(agentSession.getStatus())) {
                // log.warn("【AgentManager.getAgentSession】agent处于暂停中=====");
                throw new BizException(ErrorCode.ERROR_800010);
            } else {
                return agentSession;
            }
        }
    }

    /**
     * @Method getAliveAgentSession <br>
     * @Param agentCode <br>
     * @Return  <br>
     * @Description 查询当前所有agentSession，无关状态<br>
     * @Author Qiao jian<br>
     * @Date 2024/7/29 17:27 <br>
     * @Version V1.0<br>
     */
    public AgentSession getAliveAgentSession(String agentCode){
        AgentSession agentSession = getSession(agentCode);
        if (agentSession == null) {
            log.warn("【{}】【AgentManager.getAgentSession】agentSession不存在", agentCode);
            throw new BizException(ErrorCode.ERROR_800020);
        }
        return agentSession;
    }

    /**
     * 获取节点信息配置
     *
     * @param agentCode
     */
    public AgentSession getSession(String agentCode) {
        return agentSessionMap.get(agentCode);
    }

    public void delAgentSession(AgentSession agentSession){
        agentSessionMap.remove(agentSession.getAgentCode());
        agentSessionList.remove(agentSession);
        // 删除appSession中的有效agentSession
        List<AppConf> appConfList = agentSession.getAppConfList();
        for (AppConf appConf : appConfList) {
            AppSession appSession = appManager.getAppSession(appConf.getAppCode());
            if (appSession != null) {
                appSession.delAgentSession(agentSession);
            }
        }
    }


    /**
     * 验证节点IP 端口
     *
     * @param registerReq
     * @return
     */
    public AgentConf validAgent(RegisterReq registerReq) {
        AgentConf agentConf = this.managerService.qryAgentConfByAgentCode(registerReq.getReqCode());
        if (!registerReq.getIp().equals(agentConf.getAgentIp())) {
            log.warn("【AgentManager.validAgent】节点IP匹配失败=====");
            throw new BizException(ErrorCode.ERROR_800006);
        }

        if (!registerReq.getPort().equals(agentConf.getAgentPort())) {
            log.warn("【AgentManager.validAgent】节点端口匹配失败=====");
            throw new BizException(ErrorCode.ERROR_800008);
        }

        if (Const.AGENT_STATUS_STOP.equals(agentConf.getAgentStatus())) {
            log.warn("【AgentManager.validAgent】节点处于暂停中=====");
            throw new BizException(ErrorCode.ERROR_800010);
        }
        return agentConf;
    }

    /**
     * 验证节点token
     *
     * @param agentCode
     * @param token
     */
    public void validAgentToken(String agentCode, String token) {
        AgentSession agentSession = this.getAliveAgentSession(agentCode);
        if (!token.equals(agentSession.getToken())) {
            log.error("节点token无效或已失效，请重新注册【AgentManager.validAgentToken】agentCode: {}", agentCode);
            throw new BizException(ErrorCode.ERROR_830001);
        }
    }

    /**
     * 创建节点session
     *
     * @param agentConf
     * @return
     */
    public AgentSession createAgentSession(AgentConf agentConf) {
        log.info("创建agent session【AgentManager.createAgentSession】开始=========》");
        String agentCode = agentConf.getAgentCode();

        if (!appManager.agentHasValidApp(agentCode)) {
            log.warn("【AgentManager.createAgentSession】节点下无启动的应用agentCode: {}", agentCode);
            //告警信息，节点下无启动的应用  ？？
            throw new BizException(ErrorCode.ERROR_820010);
        }

        List<AppConf> appConfList = appManager.getAppConfList(agentCode);
        AgentSession agentSession = new AgentSession(agentConf, appConfList, this);
        return agentSession;
    }

    /**
     * 新增 agentSession 到 agentManager
     *
     * @param agentSession
     */
    public void addAgentSession(AgentSession agentSession) {
        if (agentSession == null) {
            return;
        }

        String agentStatus = agentSession.getStatus();
        if (Const.AGENT_STATUS_START.equals(agentStatus)) {
            agentSessionList.add(agentSession);
        } else if (Const.AGENT_STATUS_STOP.equals(agentStatus)) {
            notValidAgentSessionList.add(agentSession);
        }
        agentSessionMap.put(agentSession.getAgentCode(), agentSession);
    }

    /**
     * 清空 agentSession
     */
    public void clearAgentSession() {
        agentSessionMap.clear();
        agentSessionList.clear();
        notValidAgentSessionList.clear();
    }

    /**
     * 通知  matser初始化完成
     */
    public void notifyMasterInitSucc(CenterConf newCenterConf) {
        for (AgentSession agentSession : agentSessionList) {
            agentSession.masterInitSucc(newCenterConf);
        }
    }

    /**
     * 获取有效节点数
     *
     * @return
     */
    public int getValidAgentNum() {
        return ListUtil.isEmpty(agentSessionList) ? 0 : agentSessionList.size();
    }

    /**
     * 节点停用
     *
     * @param agentCode
     */
    public void stopAgent(String agentCode, String logMsg) {
        AgentSession agentSession = getSession(agentCode);
        if (null != agentSession && Const.AGENT_STATUS_START.equals(agentSession.getStatus())) {
            agentSession.setStatus(Const.AGENT_STATUS_STOP);
            notValidAgentSessionList.add(agentSession);
            agentSessionList.remove(agentSession);

            // 删除appSession中的有效agentSession
            List<AppConf> appConfList = agentSession.getAppConfList();
            for (AppConf appConf : appConfList) {
                AppSession appSession = appManager.getAppSession(appConf.getAppCode());
                if (appSession != null) {
                    appSession.delAgentSession(agentSession);
                }
            }

            this.logService.stopAgentLog(agentSession, logMsg);
        }
    }

    /**
     * 节点继续
     *
     * @param agentCode
     */
    public void continueAgent(String agentCode) {
        AgentSession agentSession = getSession(agentCode);
        if (null != agentSession && Const.AGENT_STATUS_STOP.equals(agentSession.getStatus())) {
            agentSession.setStatus(Const.AGENT_STATUS_START);
            agentSessionList.add(agentSession);
            notValidAgentSessionList.remove(agentSession);
            addAgentSessionToAppSession(agentSession);
            this.logService.continueAgentLog(agentSession);
        }
    }

    /*
     * @Method: addAgentSessionToAppSession <br>
     * @Param: [agentSession] <br>
     * @Return: void <br>
     * @Description：向AppSession中添加AgentSession<br>
     * @Author： wz.li<br>
     * @Date： 2022/11/28 19:56 <br>
     * @Version： V2.0.2<br>
     */
    private void addAgentSessionToAppSession(AgentSession agentSession) {
        List<AppConf> appConfList = agentSession.getAppConfList();
        for (AppConf appConf : appConfList) {
            AppSession appSession = appManager.getAppSession(appConf.getAppCode());
            if (appSession != null) {
                appSession.addAgentSession(agentSession);
            }
        }
    }

    /**
     * @Method: testLink
     * @Param: [agentConf]
     * @Return: boolean
     * @Description： 连接测试
     * @Author： jd.chen
     * @Date： 2021/7/5 19:54
     * @Version： V1.0
     */
    public boolean testLink(AgentConf agentConf) {
        return agentDao.testLink(agentConf);
    }

    /**
     * @Method: updateAgentStatus
     * @Param: [agentConf]
     * @Return: void
     * @Description： 更新内存中节点状态
     * @Author： jd.chen
     * @Date： 2021/7/5 19:57
     * @Version： V1.0
     */
    public void updateAgentStatus(AgentConf agentConf) {
        String agentStatus = agentConf.getAgentStatus();
        String agentCode = agentConf.getAgentCode();
        if (Const.AGENT_STATUS_START.equals(agentStatus)) {
            // 启用
            this.continueAgent(agentCode);
        } else if (Const.AGENT_STATUS_STOP.equals(agentStatus)) {
            // 停用
            this.stopAgent(agentCode, "界面停止agent");
        }
    }

    /**
     * 杀死agent上任务进程
     *
     * @param task
     */
    public boolean killTask(PeriodTask task) {
        AgentSession agentSession = this.getAgentSession(task.getAgentCode());

        TaskInfo taskInfo = new TaskInfo();
        ScheduleTask scheduleTask = new ScheduleTask();
        scheduleTask.setTaskCode(task.getTaskCode());
        scheduleTask.setBizDate(task.getBizDate());
        taskInfo.setTask(scheduleTask);
        // 远程kill任务进程
        boolean killTaskResult = agentSession.killTask(taskInfo);

        agentSession.delTaskSession(task);
        return killTaskResult;
    }

    public void delOverTsTask() {
        try {
            for (AgentSession agentSession : this.agentSessionList) {
                List<PeriodTask> taskList = agentSession.getPeriodRunningList();
                for (int i = 0; i < taskList.size(); i++) {
                    PeriodTask periodTask = taskList.get(i);
                    if (FilterTaskHelper.isOverTsTask(periodTask)) {
                        agentSession.delTaskSession(periodTask);
                    }
                }
            }
        } catch (Exception e) {
            log.error("【delOverTsTask】异常: {}", e.getMessage(), e);
        }
    }

    public AppManager getAppManager() {
        return appManager;
    }

    public AgentDao getAgentDao() {
        return agentDao;
    }

    public LogService getLogService() {
        return logService;
    }

    public Map<String, AgentSession> getAgentSessionMap() {
        return agentSessionMap;
    }

    public List<AgentSession> getAgentSessionList() {
        return agentSessionList;
    }

    public List<AgentSession> getNotValidAgentSessionList() {
        return notValidAgentSessionList;
    }

    public int getDisSendFailLimit() {
        return disSendFailLimit;
    }

    public int getDisSendSleep() {
        return disSendSleep;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static AgentManager getInstance() {
        return context.getBean(AgentManager.class);
    }
}
